home *** CD-ROM | disk | FTP | other *** search
/ MacGames Sampler / PHT MacGames Bundle.iso / MacSource Folder / Samples from the CD / Editors / emacs / Emacs-1.14b1-sources / sources / unix-emulation-src / events.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-31  |  12.2 KB  |  551 lines  |  [TEXT/EMAC]

  1. /*
  2.  * Copyright (C) 1993, 1994 Marc Parmet.
  3.  * This file is part of the Macintosh port of GNU Emacs.
  4.  *
  5.  * GNU Emacs is distributed in the hope that it will be useful,
  6.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  7.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  8.  * GNU General Public License for more details.
  9.  */
  10.  
  11. #if defined(THINK_C)
  12. #include <MacHeaders>
  13. #else
  14. #include <Types.h>
  15. #include <Memory.h>
  16. #include <Quickdraw.h>
  17. #include <Windows.h>
  18. #include <TextEdit.h>
  19. #include <LowMem.h>
  20. #include <Dialogs.h>
  21. #include <ToolUtils.h>
  22. #endif
  23.  
  24. #include <Retrace.h>
  25. #include <GestaltEqu.h>
  26. #include <AppleEvents.h>
  27. #include "unix-types.h"
  28. #include "unix-constants.h"
  29. #include "kbd-patch-data.h"
  30. #include "emacs-version.h"
  31.  
  32. #define QUIT_MODIFIERS controlKey
  33. #define QUIT_CHAR 'g'
  34.  
  35. extern int Vaccept_high_level_events;
  36. extern int Vmodifier_vector;
  37.  
  38. char got_interrupt_from_terminal;
  39. static short cached_event_head,cached_event_tail; // Queue is empty when equal
  40. static short cached_key_head,cached_key_tail; // Queue is empty when equal
  41. #define MAX_KEYS 50
  42. #define MAX_EVENTS 50
  43. static struct {
  44.     EventRecord e;
  45.     AppleEvent ae,reply;
  46.     long refCon;
  47. } cached_events[MAX_EVENTS];
  48. static char cached_keys[MAX_KEYS];
  49. static char clipboard_fix,clipboard_fix_update_contents;
  50.  
  51. WindowPtr console_window(),tty_window();
  52.  
  53. static int
  54. typed_to_denoted(int modifiers)
  55. {
  56.     register int i;
  57.     register struct keyboard_patch_vector *v;
  58.  
  59.     if (Vmodifier_vector == 0) return modifiers;
  60.     if (modifiers == 0) return 0;
  61.  
  62.     v = MODIFIER_XVECTOR(Vmodifier_vector);
  63.     for (i = 0; i<v->size; ++i)
  64.         if (v->contents[i].typed == modifiers)
  65.             return v->contents[i].denoted;
  66.  
  67.     return 0;
  68. }
  69.  
  70. static void
  71. do_content(EventRecord *e,WindowPtr w)
  72. {
  73.     if (w == tty_window())
  74.         tty_content();
  75.     else if (w == console_window())
  76.         console_content(e);
  77. }
  78.  
  79. static void
  80. do_update(WindowPtr w)
  81. {
  82.     if (w == tty_window())
  83.         tty_update();
  84.     else if (w == console_window())
  85.         console_update();
  86.     else {
  87.         BeginUpdate(w);
  88.         EndUpdate(w);
  89.     }
  90. }
  91.  
  92. static void
  93. do_activate(WindowPtr w,int activate)
  94. {
  95.     if (w == tty_window())
  96.         tty_activate();
  97.     else if (w == console_window())
  98.         console_activate(activate);
  99.  
  100.     // fixup_menus();
  101. }
  102.  
  103. static void
  104. do_drag(EventRecord *e,WindowPtr w)
  105. {
  106.     if (w == tty_window())
  107.         tty_drag(e);
  108.     else if (w == console_window())
  109.         console_drag(e);
  110. }
  111.  
  112. extern int input_pending;
  113.  
  114. static void
  115. do_menu(long choice)
  116. {
  117.     unsigned char s[256];
  118.     short menu,item;
  119.  
  120.     if (FrontWindow() == console_window()) {
  121.         input_pending = 0;
  122.         do_menu_internal(choice);
  123.     }
  124.     else {
  125.         menu = HiWord(choice);
  126.         item = LoWord(choice);
  127.         GetItem(GetMHandle(menu),item,s);
  128.         if (!pstrcmp(s,"\pClose")) {
  129.             /* This is an awful fix.  Find something better. */
  130.             HideWindow(tty_window());
  131.             HiliteMenu(0);
  132.         }
  133.         else {
  134.             SelectWindow(console_window());
  135.             do_menu(choice);
  136.         }
  137.     }
  138. }
  139.  
  140. static void
  141. refresh_screen(void)
  142. {
  143.     /* This can result in a reentrant call to the kernel.  Beware. */
  144.     input_pending = 0;
  145.     redisplay();
  146. }
  147.  
  148. static void
  149. do_mouseDown(EventRecord *e)
  150. {
  151.     short partCode;
  152.     WindowPtr w;
  153.     long choice;
  154.     
  155.     switch (partCode = FindWindow(e->where,&w)) {
  156.     case inMenuBar:
  157.         do_MenuSelect_before_hooks();
  158.         choice = MenuSelect(e->where);
  159.         if (HiWord(choice) != 0) do_menu(choice);
  160.         break;
  161.     case inGoAway:
  162.         tty_goaway(e);
  163.         break;
  164. /*    case inDrag:
  165.         do_drag(e,w);
  166.         break; */
  167.     case inGrow:
  168.         console_grow(e);
  169.         break;
  170.     case inContent:
  171.         do_content(e,w);
  172.         break;
  173.     }
  174. }
  175.  
  176. static void
  177. enqueue_key(char c)
  178. {
  179.     if ((cached_key_head+1) % MAX_KEYS == cached_key_tail) return;
  180.     cached_keys[cached_key_head] = c;
  181.     cached_key_head = (cached_key_head + 1) % MAX_KEYS;
  182. }
  183.  
  184. pascal short
  185. ae_receive_func(AppleEvent *ae,AppleEvent *reply,long refCon)
  186. {
  187.     cached_events[cached_event_head].ae = *ae;
  188.     cached_events[cached_event_head].reply = *reply;
  189.     cached_events[cached_event_head].refCon = refCon;
  190.     AESuspendTheCurrentEvent(ae);
  191.     return noErr;
  192. }
  193.  
  194. static void
  195. do_event(EventRecord *e,AppleEvent *ae,AppleEvent *reply,long refCon)
  196. {
  197.     char c;
  198.     int err;
  199.     long choice;
  200.     short modifiers;
  201.     unsigned char virtual_keycode;
  202.     
  203.     switch (e->what) {
  204.     case mouseDown:
  205.         do_mouseDown(e);
  206.         refresh_screen();
  207.         break;
  208.     case kHighLevelEvent:
  209.     {
  210.         extern ae_receive_func2();
  211.         static AEEventHandlerUPP ae_receive_func2_upp;
  212.         if (ae_receive_func2_upp == 0L)
  213.             ae_receive_func2_upp = NewAEEventHandlerProc(ae_receive_func2);
  214.         err = AEResumeTheCurrentEvent(ae,reply,ae_receive_func2_upp,refCon);
  215.         refresh_screen();
  216.         break;
  217.     }
  218.     case keyDown:
  219.     case autoKey:
  220.         modifiers = typed_to_denoted(e->modifiers & MODIFIER_KEYS);
  221.         if (modifiers == cmdKey) {
  222.             // Command key combination
  223.             choice = MenuKey(e->message & charCodeMask);
  224.             if (HiWord(choice) != 0) {
  225.                 do_menu(choice);
  226.                 refresh_screen();
  227.             }
  228.         }
  229.         else {
  230.             // Regular keystroke
  231.             ObscureCursor();
  232.  
  233.             if (modifiers & metaKey) enqueue_key(27);
  234.             virtual_keycode = (e->message >> 8) & 0x7f;
  235.             if (virtual_keycode >= 0x40) {
  236.                 enqueue_key('x' & 0x1f);
  237.                 enqueue_key('*');
  238.                 c = virtual_keycode;
  239.                 if (!(modifiers & shiftKey)) c -= 0x40;
  240.                 enqueue_key(c);
  241.             }
  242.             else {
  243.                 c = e->message & charCodeMask;
  244.                 if (virtual_keycode == 0x33) c = 0x7f; // delete, above return
  245.                 if (c == '\015' && modifiers == shiftKey) c = '\012';
  246.                 if (modifiers & controlKey) c &= 0x1f;
  247.                 enqueue_key(c);
  248.             }
  249.         }
  250.         break;
  251.     }
  252. }
  253.  
  254. static void
  255. enqueue_event(EventRecord *e)
  256. {
  257.     if ((cached_event_head+1) % MAX_EVENTS != cached_event_tail) {
  258.         cached_events[cached_event_head].e = *e;
  259.         if (e->what == kHighLevelEvent) AEProcessAppleEvent(e);
  260.         cached_event_head = (cached_event_head + 1) % MAX_EVENTS;
  261.     }
  262. }
  263.  
  264. static int
  265. emacs_is_front_process(void)
  266. {
  267.     short err;
  268.     Boolean same;
  269.     ProcessSerialNumber psn1,psn2;
  270.  
  271.     err = GetFrontProcess(&psn1);
  272.     if (err) return 1;
  273.     err = GetCurrentProcess(&psn2);
  274.     if (err) return 1;
  275.     err = SameProcess(&psn1,&psn2,&same);
  276.     return err || same;
  277. }
  278.  
  279. void
  280. read_events(int yield)
  281. {
  282.     WindowPtr w;
  283.     EventRecord e;
  284.     short partCode;
  285.     Boolean have_event;
  286.     short mask,modifiers,yieldtime;
  287.     static int time_of_last_keystroke,time_of_last_WaitNextEvent,
  288.         time_of_last_highlevel;
  289.  
  290.     if (emacs_is_front_process()) {
  291.         /* It's possible we'll get to this point while in a modal dialog called
  292.            up from elisp.  Garbage collection, by printing the message "Garbage
  293.            collecting...", will bring us here, as will any I/O.  It's not good
  294.            to call WaitNextEvent when a modal dialog is up, so we try to detect
  295.            this case, and return immediately. */
  296.         if (LMGetWindowList()->windowKind == dialogKind) return;
  297.         
  298.         if (FrontWindow() == tty_window())
  299.             yieldtime = 0;
  300.         else if (yield) {
  301.             /* Console is frontmost.  Emacs entered the kernel, every entry
  302.                to the kernel brings us here.
  303.                Every 120 ticks, yield for 15 ticks. */
  304.             if (time_of_last_WaitNextEvent + 120 > TickCount()) return;
  305.             yieldtime = 15;
  306.         }
  307.         else {
  308.             /* Console is frontmost, Emacs is calling 'read' to get keystrokes.
  309.                Every 2 ticks, get input trying not to yield. */
  310.             if (time_of_last_keystroke + 2 >= TickCount()) return;
  311.             yieldtime = 0;
  312.         }
  313.     }
  314.     else {
  315.         /* Emacs is in the background.  Take 1/15 of a second but then
  316.            yield for 30 ticks, unless we've been busy lately. */
  317.         if (time_of_last_WaitNextEvent + 1 >= TickCount()) return;
  318.         if (time_of_last_highlevel + 180 > TickCount())
  319.             yieldtime = 0;
  320.         else {
  321.             yieldtime = 30;
  322.         }
  323.     }
  324.  
  325.     mask = everyEvent;
  326.     if (!Vaccept_high_level_events) mask &= ~highLevelEventMask;
  327.  
  328.     while (1) {
  329.         have_event = WaitNextEvent(mask,&e,yieldtime,0L);
  330.         time_of_last_WaitNextEvent = e.when;
  331.         if (!have_event) {
  332.             SetCursor(&qd.arrow);
  333.             return;
  334.         }
  335.  
  336.         switch (e.what) {
  337.         case nullEvent:
  338.             return;
  339.         case updateEvt:
  340.             do_update((WindowPtr)e.message);
  341.             break;
  342.         case activateEvt:
  343.             do_activate((WindowPtr)e.message,e.modifiers & activeFlag);
  344.             break;
  345.         case osEvt:
  346.             /* This is not what is described in IM VI, p. 5-20,
  347.                which seems to be wrong. */
  348.             if (*(char *)&e.message == suspendResumeMessage) {
  349.                 if (BitTst(&e.message,32 - resumeFlag)) {
  350.                     /* Resume */
  351.                     clipboard_fix = 1;
  352.                     clipboard_fix_update_contents =
  353.                         BitTst(&e.message,32 - convertClipboardFlag);
  354.                     do_activate(FrontWindow(),1);
  355.                 }
  356.                 else {
  357.                     /* Suspend */
  358.                     clipboard_fix = 1;
  359.                     clipboard_fix_update_contents = 0;
  360.                     do_activate(FrontWindow(),0);
  361.                 }
  362.             }
  363.             break;
  364.         case kHighLevelEvent:
  365. #if 0
  366.             asm {
  367.                 move.l e.message,d0
  368.                 move.l e.where,d1
  369.             }
  370.             DebugStr("\pEmacs got high level event;d0;d1");
  371. #endif
  372.             time_of_last_highlevel = e.when;
  373.             enqueue_event(&e);
  374.             break;
  375.         case mouseDown:
  376.             switch (partCode = FindWindow(e.where,&w)) {
  377.             case inMenuBar:
  378.             case inGoAway:
  379.             case inContent:
  380.             case inGrow:
  381.                 enqueue_event(&e);
  382.                 break;
  383.             case inDrag:
  384.                 do_drag(&e,w);
  385.                 break;
  386.             }
  387.             break;
  388.         case keyDown:
  389.         case autoKey:
  390.             time_of_last_keystroke = e.when;
  391.             modifiers = typed_to_denoted(e.modifiers & MODIFIER_KEYS);
  392.             if (QUIT_MODIFIERS != 0 && modifiers == QUIT_MODIFIERS &&
  393.                     (char)e.message == QUIT_CHAR)
  394.                 got_interrupt_from_terminal = 1;
  395.             else
  396.                 enqueue_event(&e);
  397.             break;
  398.         }
  399.     }
  400. }
  401.  
  402. // This is how we catch control-g when hung in a loop.
  403.  
  404. static struct VBLTask probe;
  405.  
  406. static void
  407. do_quit_char_probe(void)
  408. {
  409.     EvQElPtr q;
  410.     
  411.     probe.vblCount = 15;
  412.  
  413.     if (QUIT_MODIFIERS == 0) return;
  414.     for (q = (EvQElPtr)GetEvQHdr()->qHead; q != 0L; q = (EvQElPtr)q->qLink)
  415.         if (q->evtQWhat == keyDown &&
  416.                 (Vmodifier_vector == 0 ?
  417.                     (q->evtQModifiers & MODIFIER_KEYS) == QUIT_MODIFIERS &&
  418.                         (char)q->evtQMessage == (QUIT_CHAR & 0x1f) :
  419.                     typed_to_denoted(q->evtQModifiers & MODIFIER_KEYS) == QUIT_MODIFIERS &&
  420.                         (char)q->evtQMessage == QUIT_CHAR))
  421.             /* It is critical here that we use the far memory model and avoid
  422.                addressing off of a5. */
  423.             got_interrupt_from_terminal = 1;
  424. }
  425.  
  426. void
  427. unix_init_kbd(void)
  428. {
  429.     short err;
  430.     struct keyboard_patch_data *kbpd;
  431.     static VBLUPP do_quit_char_probe_upp;
  432.  
  433.     if (do_quit_char_probe_upp == 0L)
  434.         do_quit_char_probe_upp = NewVBLProc(do_quit_char_probe);
  435.  
  436.     probe.qLink = 0L;
  437.     probe.qType = vType;
  438.     probe.vblAddr = do_quit_char_probe_upp;
  439.     probe.vblCount = 15;
  440.     probe.vblPhase = 0;
  441.     
  442. //    err = VInstall((QElemPtr)&probe);
  443. //    if (err) ExitToShell();
  444.  
  445.     err = Gestalt('EMAc',(long *)&kbpd);
  446.     if (err || kbpd->version != emacs_version_complete) {
  447.         InitCursor();
  448.         switch (Alert(137,0L)) {
  449.         case 1: return;
  450.         case 2: ExitToShell();
  451.         }
  452.     }
  453.  
  454.     kbpd->v = (long *)&Vmodifier_vector;
  455.     err = GetCurrentProcess(&kbpd->emacs_psn);
  456.     if (err) ExitToShell();
  457. }
  458.  
  459. static int
  460. user_cancelled(void)
  461. {
  462.     register EvQElPtr q;
  463.  
  464.     for (q = (EvQElPtr)GetEvQHdr()->qHead; q != 0L; q = (EvQElPtr)q->qLink)
  465.         if (q->evtQWhat == keyDown &&
  466.                 (((q->evtQModifiers & cmdKey) && (char)q->evtQMessage == '.') ||
  467.                  (char)q->evtQMessage == (QUIT_CHAR & 0x1f)))
  468.             return 1;
  469.     
  470.     return 0;
  471. }
  472.  
  473. pascal Boolean
  474. ae_send_idle_function(EventRecord *e,long *sleepTime,RgnHandle *mouseRgn)
  475. {
  476.     *sleepTime = 30;
  477.     *mouseRgn = 0L;
  478.     
  479.     if (user_cancelled()) return 1;
  480.  
  481.     switch (e->what) {
  482.     case nullEvent:
  483.         spin_beachball();
  484.         break;
  485.     case osEvt:
  486.         break;
  487.     case updateEvt:
  488.         do_update((WindowPtr)e->message);
  489.         break;
  490.     case activateEvt:
  491.         do_activate((WindowPtr)e->message,e->modifiers & activeFlag);
  492.         break;
  493.     }
  494.  
  495.     return 0;
  496. }
  497.  
  498. int
  499. number_of_pending_events(void)
  500. {
  501.     int events_available;
  502.     
  503.     read_events(0);
  504.     events_available = (cached_event_head + MAX_KEYS - cached_event_tail) % MAX_KEYS;
  505.     return cached_key_head != cached_key_tail || clipboard_fix ||
  506.                 (events_available > 0 &&
  507.                 !(events_available == 1 &&
  508.                     cached_events[cached_event_tail].e.message == kCoreEventClass &&
  509.                     *(long *)&cached_events[cached_event_tail].e.where == kAEOpenApplication));
  510. }
  511.  
  512. int
  513. handle_all_events_but_keystrokes(char *p,int n)
  514. {
  515.     int m;
  516.     long refCon;
  517.     EventRecord e;
  518.     AppleEvent ae,reply;
  519.  
  520.     read_events(0);
  521.  
  522.     if (clipboard_fix) {
  523.         clipboard_fix = 0;
  524.         fixup_clipboard(clipboard_fix_update_contents);
  525.         refresh_screen();
  526.     }
  527.  
  528.     while (cached_event_head != cached_event_tail) {
  529.         e = cached_events[cached_event_tail].e;
  530.         ae = cached_events[cached_event_tail].ae;
  531.         reply = cached_events[cached_event_tail].reply;
  532.         refCon = cached_events[cached_event_tail].refCon;
  533.         cached_event_tail = (cached_event_tail + 1) % MAX_EVENTS;
  534.         do_event(&e,&ae,&reply,refCon);
  535.     }
  536.  
  537.     m = 0;
  538.     while (cached_key_head != cached_key_tail && m != n) {
  539.         p[m++] = cached_keys[cached_key_tail];
  540.         cached_key_tail = (cached_key_tail + 1) % MAX_KEYS;
  541.     }
  542.  
  543.     return m;
  544. }
  545.  
  546. void
  547. discard_tty_input(void)
  548. {
  549.     FlushEvents(keyDownMask | autoKeyMask,0);
  550. }
  551.